package com.smsc.headend.task.engine.handler;

import com.smsc.headend.common.enums.errorcode.TaskHandlerErrorCode;
import com.smsc.headend.common.utils.RedisUtils;
import com.smsc.headend.module.common.entity.DeviceOperation;
import com.smsc.headend.module.data.enums.DictionaryType;
import com.smsc.headend.module.data.enums.OperationGroup;
import com.smsc.headend.module.data.enums.OperationName;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.task.engine.exception.UDISTaskHandlerException;
import com.smsc.headend.task.engine.handler.impl.ActionSuccessHandler;
import com.smsc.headend.task.engine.handler.impl.ReadProfileCaptureObjectsHandler;
import com.smsc.headend.task.engine.handler.impl.ReadProfilePeriodHandler;
import com.smsc.headend.task.engine.handler.impl.ReadRegisterValueHandler;
import com.smsc.headend.task.engine.handler.impl.ansi.GetLpSettingHandler;
import com.smsc.headend.task.engine.handler.impl.ansi.GetLpStatusHandler;
import com.smsc.headend.task.engine.handler.impl.ansi.GetOffsetHandler;
import com.smsc.headend.task.engine.handler.impl.collection.ReadLoadProfileBufferHandler;
import com.smsc.headend.task.engine.handler.impl.collection.ReadScheduleReadBufferHandler;
import com.smsc.headend.task.engine.handler.impl.deviceconfig.KeyTransferActionHandler;
import com.smsc.headend.task.engine.handler.impl.whitelist.ReadMeterListHandler;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.asset.AssetService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class TaskResultHandlerFactory {
    public static final String KEY_GROUP_FORMAT = "%s:%s:%s";
    @Autowired
    RedisUtils redisUtils;
    @Autowired
    FeignAssetManagementService assetManagementService;
    @Autowired
    AutowireCapableBeanFactory autowireCapableBeanFactory;
    @Autowired
    AssetService assetService;
    private Map<String, Class<TaskHandler>> executorMap = new HashMap<>();

    @PostConstruct
    public void init() {
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.ODRReadProfiles, OperationName.ReadData, 0), ReadProfilePeriodHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.ODRReadProfiles, OperationName.ReadData, 1), ReadProfileCaptureObjectsHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.ODRReadProfiles, OperationName.ReadLoadProfile, 2), ReadLoadProfileBufferHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.ODRReadProfiles, OperationName.GetLpSetting, 0), GetLpSettingHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.ODRReadProfiles, OperationName.GetLpStatus, 1), GetLpStatusHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.ODRReadProfiles, OperationName.GetOffset, 2), GetOffsetHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.ScheduleReadProfiles, OperationName.ReadLoadProfile, 0), ReadLoadProfileBufferHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.ScheduleReadProfiles, OperationName.ReadDCUCollectionData, 0), ReadLoadProfileBufferHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.ReadRegister, OperationName.ReadData, 0), ReadRegisterValueHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.DCUGetMeterList, OperationName.ReadData, 0), ReadMeterListHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.GetMeterMeasProfileConfig, OperationName.ReadProfilePeriod, 0), ReadProfilePeriodHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.GetMeterMeasProfileConfig, OperationName.ReadProfileCaptureObjects, 1), ReadProfileCaptureObjectsHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.SetMeterMeasProfileConfig, OperationName.SetProfilePeriod, 0), ActionSuccessHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.SetMeterMeasProfileConfig, OperationName.SetProfileCaptureObjects, 1), ActionSuccessHandler.class);
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.ScheduleRead, OperationName.ScheduleRead, 0), ReadScheduleReadBufferHandler.class);//巡检
        this.registerExecutor(String.format(KEY_GROUP_FORMAT, OperationGroup.SecuritySetup, OperationName.ActionKeyTransfer, 0), KeyTransferActionHandler.class);
    }

    public Boolean registerExecutor(String name, Class executor) {
        if (executorMap.containsKey(name)) {
            return false;
        }
        executorMap.put(name, executor);
        return true;
    }


    public TaskHandler getHandler(Task task, AtomicTask atomicTask, String handlerClass) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, UDISTaskHandlerException, ClassNotFoundException {
        Long groupId = atomicTask.getGroupId();
        Long operationId = atomicTask.getOperationId();
        Integer seq = atomicTask.getSeq() == null ? 0 : atomicTask.getSeq();
        DeviceOperation groupDict = assetService.getDictionary(groupId, DictionaryType.OperationGroup.getType());
        DeviceOperation operationDict = assetService.getDictionary(operationId, DictionaryType.Operation.getType());

        String handlerKey = String.format(KEY_GROUP_FORMAT, groupDict.getOptName(), operationDict.getOptName(), seq);
        Class<TaskHandler> taskHandlerClass = handlerClass == null ? this.executorMap.get(handlerKey) : (Class<TaskHandler>) Class.forName(handlerClass);
        if (taskHandlerClass == null) {
            log.error("handler: handlerClass={},handler-key={}", handlerClass, handlerKey);
            throw new UDISTaskHandlerException(TaskHandlerErrorCode.TASK_HANDLER_NOT_EXISTS.getErrorCode());
        }
        TaskHandler executor = taskHandlerClass.getDeclaredConstructor().newInstance();
        autowireCapableBeanFactory.autowireBean(executor);
        return executor;
    }
}
